#include <iostream>
#include "TableManager.h"

TableManager::TableManager()
{
	currentAddress = 0;
	createNewTable();
	currentFunction = NULL;
}

TableManager::~TableManager()
{
#if DEBUG_SYM_TAB
	std::cout << "\n----------------------------- Global Table -----------------------------\n" 
			  << *currentTable 
			  << "\n------------------------------------------------------------------------\n";
#endif
	
	for(SymTabVec::const_iterator i=inScope.begin();
		i!=inScope.end();
		++i)
	{
		delete(*i);
	}
	
	for(SymTabVec::const_iterator o=outOfScope.begin();
		o!=outOfScope.end();
		++o)
	{
		delete(*o);
	}
}

void TableManager::createNewTable() {
	currentTable = new SymbolTable();
	inScope.push_back(currentTable);
}

void TableManager::discardCurrentTable() {
	// not allowed to pop the globals table out of scope
	if(inScope.size() > 1) {
#if DEBUG_SYM_TAB
		std::cout << "----------------------------- Table " 
			<< outOfScope.size()+1 << " -----------------------------\n" 
			<< *currentTable << "\n";
#endif
		outOfScope.push_back(inScope.back());
		inScope.pop_back();
		currentTable = inScope.back();
		
		if(inScope.size() == 1 && currentFunction) {
			notifyFunctionObservers( currentFunction->getLabel(), currentAddress );
		}
	}
}

void TableManager::insert(std::string identifier, TableEntry* tabEntry) {
	if(tabEntry->getEntryType() == TableEntry::FUNCTION) {
		currentAddress = FUNCTION_BASE_ADDRESS;
		currentFunction = (FunctionEntry*)tabEntry;
	} else {
		currentAddress = tabEntry->setAddress( getNextAddress() );
	}
	currentTable->insert( identifier, tabEntry );
}

void TableManager::insert(Token &tkIdentifier, TableEntry* tabEntry) {
	if(tabEntry->getEntryType() == TableEntry::FUNCTION) {
		currentAddress = FUNCTION_BASE_ADDRESS;
		currentFunction = (FunctionEntry*)tabEntry;
	} else {
		currentAddress = tabEntry->setAddress( getNextAddress() );
	}
	currentTable->insert( tkIdentifier, tabEntry );
}

bool TableManager::search(std::string identifier, TableEntry* &tabEntry) {
	bool retVal = false;
	SymTabVec::reverse_iterator table = inScope.rbegin();
	
	while(table!=inScope.rend()) {
		retVal = (*table)->search(identifier, tabEntry);
		if(retVal) return true;
		++table;
	}
	return retVal;
}

bool TableManager::search(Token &tkIdentifier) {
	TableEntry* dummy;
	return search(tkIdentifier, dummy);
}

bool TableManager::search(Token &tkIdentifier, TableEntry* &tabEntry) {
	bool retVal = false;
	SymTabVec::reverse_iterator table = inScope.rbegin();
	
	while(table!=inScope.rend()) {
		retVal = (*table)->search(tkIdentifier, tabEntry);
		if(retVal) return true;
		++table;
	}
	return retVal;
}

int TableManager::getNextAddress() {
	int retVal = currentAddress;
	currentAddress += ADDRESS_INCREMENT;
	return retVal;
}

const FunctionEntry* const TableManager::getCurrentFunction() {
	return currentFunction;
}

std::ostream& TableManager::inserter(std::ostream &os) const {
	return os << *currentTable;
}

void TableManager::notifyFunctionObservers(std::string funcLabel, int funcSize) {
	for(std::vector<FunctionObserver*>::iterator i=functionObservers.begin();
			i!=functionObservers.end();
			++i)
	{
		(*i)->updateFunction(funcLabel, funcSize);
	}
}

void TableManager::registerObserver(FunctionObserver* o) {
	functionObservers.push_back(o);
}